#include <QDebug>
#include <QFile>
#include <QPluginLoader>
#include <QMdiSubWindow>
#include <QMessageBox>
#include <QDir>
#include <QCloseEvent>
#include <QScrollBar>
#include <QTextCodec>
#include <QtDesigner/QDesignerFormEditorInterface>
#include <QtDesigner/QDesignerComponents>
#include <QtDesigner/QDesignerWidgetBoxInterface>
#include <QtDesigner/QDesignerFormEditorPluginInterface>
#include <QtDesigner/QDesignerFormWindowManagerInterface>
#include <QtDesigner/QDesignerObjectInspectorInterface>
#include <QtDesigner/QDesignerPropertyEditorInterface>

#include <QStringBuilder>
#include <QProcess>
#include "internals/qdesigner_integration_p.h"
#include "internals/pluginmanager_p.h"
#include "internals/formwindowbase_p.h"
#include "StatusBar.h"
#include "Include/Project.h"
#include "Include/Settings.h"

#include "Designer.h"
#include "ui_Designer.h"

class PyNotoIntegration: public qdesigner_internal::QDesignerIntegration
{
public:
    PyNotoIntegration(QDesignerFormEditorInterface *core, QObject *parent = 0):
        qdesigner_internal::QDesignerIntegration(core, parent)
    {
        setSlotNavigationEnabled(true);
    }
};

namespace Plugins
{
static QDesignerFormEditorInterface *_iface = NULL;


Designer::Designer(QWidget *parentWidget) :
    QWidget(parentWidget),
    ui(new Ui::Designer),
    _form(NULL)
{
    ui->setupUi(this);
    ui->splitter_2->setStretchFactor(1, 100);

    if (!_iface){
        _iface = QDesignerComponents::createFormEditor(parentWidget);
        _iface->setTopLevel(parentWidget);
        QDesignerComponents::createTaskMenu(_iface, parentWidget);
        QDesignerComponents::initializePlugins(_iface);
        QDesignerComponents::initializeResources();
    }


    _wb = QDesignerComponents::createWidgetBox(_iface, this);
    ui->widgetsPlace->layout()->addWidget(_wb);
    _iface->setWidgetBox(_wb);

    _oi = QDesignerComponents::createObjectInspector(_iface, this);
    ui->objectsPlace->layout()->addWidget(_oi);
    _iface->setObjectInspector(_oi);

    _pe = QDesignerComponents::createPropertyEditor(_iface, this);
    ui->propertyPlace->layout()->addWidget(_pe);
    _iface->setPropertyEditor(_pe);


    _ae = QDesignerComponents::createActionEditor(_iface, this);
    ui->actionTabPlace->layout()->addWidget((QWidget*)_ae);
    _iface->setActionEditor(_ae);

    ui->slotTabPLace->layout()->addWidget(QDesignerComponents::createSignalSlotEditor(_iface, this));

    _designer = new PyNotoIntegration(_iface, this);
    _iface->setIntegration(_designer);

    QList<QObject*> plugins = QPluginLoader::staticInstances();
    plugins += _iface->pluginManager()->instances();

    foreach (QObject *plugin, plugins) {
        if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(plugin)) {
            if (!formEditorPlugin->isInitialized()){
                formEditorPlugin->initialize(_iface);
            }
        }
    }

    connect(_designer->core()->formWindowManager()->actionUndo(), SIGNAL(changed()), SLOT(onUndoAvailable()));
    connect(_designer->core()->formWindowManager()->actionRedo(), SIGNAL(changed()), SLOT(onRedoAvailable()));
    connect(_designer->core()->formWindowManager()->actionCopy(), SIGNAL(changed()), SLOT(onCopyAvailable()));
    connect(_designer->core()->formWindowManager()->actionPaste(), SIGNAL(changed()), SLOT(onPasteAvailable()));
    connect(_designer, SIGNAL(navigateToSlot(QString,QString,QStringList)), SLOT(onNavigateToSlot(QString,QString,QStringList)));
}

QWidget * Designer::widget()
{
    return this;
}

void Designer::setProject(Project *prj)
{
    _project = prj;
}

void Designer::showEvent(QShowEvent *)
{
    ui->splitter_2->setSizes(QList<int>() << 250 << ui->splitter_2->width() - 450 << 250);
}

Designer::~Designer()
{
    delete ui;
    delete _form;
    delete _designer;
}

bool Designer::loadFile(const QString & fileName)
{
    if (!QFile::exists(fileName))
        return false;

    if (_project){
        QString displayName = QDir(_project->path()).relativeFilePath(fileName);
        _bar->setFileName(displayName);
    } else {
        _bar->setFileName(fileName);
    }

    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
    _fileName = fileName;
    _form = qobject_cast<qdesigner_internal::FormWindowBase *>(_iface->formWindowManager()->createFormWindow(this));
    _form->setFileName(_fileName);
    //_form->addAction(_editTabAction);

    QFile f(fileName);
    f.open(QIODevice::ReadOnly | QIODevice::Text);
    _form->setContents(f.readAll());
    f.close();

    qdesigner_internal::FormWindowBase::setupDefaultAction(_form);
    _designer->setupFormWindow(_form);

    QMdiSubWindow *wnd = ui->formPlace->addSubWindow(_form, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
    const QSize containerSize = _form->mainContainer()->size();
    const QSize containerMinimumSize = _form->mainContainer()->minimumSize();
    const QSize containerMaximumSize = _form->mainContainer()->maximumSize();
    const QSize decorationSize = wnd->geometry().size() - wnd->contentsRect().size();

    wnd->resize(containerSize+decorationSize);
    wnd->setMinimumSize(containerMinimumSize+decorationSize);

    if( containerMaximumSize == QSize(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX) )
        wnd->setMaximumSize(containerMaximumSize);
    else
        wnd->setMaximumSize(containerMaximumSize+decorationSize);
    wnd->setWindowTitle( _form->mainContainer()->windowTitle() );
    wnd->show();

    _iface->formWindowManager()->setActiveFormWindow(_form);
    //_form->editWidgets();
    connect(_form, SIGNAL(changed()), SLOT(onFormChanged()));
    _form->setDirty(false);
    return true;
}

bool Designer::saveFile()
{
    QFile file(_fileName);
    if (file.open(QIODevice::WriteOnly | QIODevice::Text)){
        file.write(_form->contents().toUtf8());
        file.close();
        _form->setDirty(false);
        onFormChanged();
        renderPyFile();
        return true;
    }
    return false;
}

void Designer::onFormChanged()
{
    emit fileChanged(_form->isDirty());
}

void Designer::closeEvent(QCloseEvent *event)
{
    if (_form->isDirty()){
        QMessageBox::StandardButton res = QMessageBox::question(this, "Close editor",
                        QString("The document \"%1\" has unsaved changes. Would you like to save them?").arg(_fileName),
                        QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

        if ( res == QMessageBox::Ok){
            saveFile();
        }

        if (res == QMessageBox::Cancel){
            event->ignore();
        }
    }
}

bool Designer::isModified()
{
    return _form->isDirty();
}

void Designer::activate()
{
    //_designer->initializePlugins(_form);//activateWidget(_form);
    //_designer->core()->formWindowManager()->setActiveFormWindow(_form);
    _iface->setIntegration(_designer);
    _iface->setObjectInspector(_oi);
    _iface->setWidgetBox(_wb);
    _iface->setPropertyEditor(_pe);
    _iface->setActionEditor(_ae);
    //_iface->setTopLevel(this);

    _iface->formWindowManager()->setActiveFormWindow(_form);

    emit undoAvailable(_designer->core()->formWindowManager()->actionUndo()->isEnabled());
    emit redoAvailable(_designer->core()->formWindowManager()->actionRedo()->isEnabled());
    emit copyAvailable(_designer->core()->formWindowManager()->actionCopy()->isEnabled());
    emit pasteAvailable(_designer->core()->formWindowManager()->actionPaste()->isEnabled());
    emit fileChanged(isModified());
}

void Designer::onUndoAvailable()
{
    emit undoAvailable(_designer->core()->formWindowManager()->actionUndo()->isEnabled());
}

void Designer::onRedoAvailable()
{
    emit redoAvailable(_designer->core()->formWindowManager()->actionRedo()->isEnabled());
}

void Designer::onCopyAvailable()
{
    emit copyAvailable(_designer->core()->formWindowManager()->actionCopy()->isEnabled());
}

void Designer::onPasteAvailable()
{
    emit pasteAvailable(_designer->core()->formWindowManager()->actionPaste()->isEnabled());
}

void Designer::undo()
{
    _designer->core()->formWindowManager()->actionUndo()->trigger();
    emit fileChanged(_form->isDirty());
}

void Designer::redo()
{
    _designer->core()->formWindowManager()->actionRedo()->trigger();
    emit fileChanged(_form->isDirty());
}

void Designer::copy()
{
    _designer->core()->formWindowManager()->actionCopy()->trigger();
}

void Designer::cut()
{
    _designer->core()->formWindowManager()->actionCut()->trigger();
}

void Designer::paste()
{
    _designer->core()->formWindowManager()->actionPaste()->trigger();
}

void Designer::del()
{
    _designer->core()->formWindowManager()->actionDelete()->trigger();
}

void Designer::selectAll()
{
    _designer->core()->formWindowManager()->actionSelectAll()->trigger();
}

void Designer::setStatusBar(StatusBar * bar)
{
    _bar = bar;
    connect(_bar, SIGNAL(switchWidgets()), SLOT(onSwitchWidgets()));
    connect(_bar, SIGNAL(switchTabOrder()), SLOT(onSwitchTabOrder()));
    connect(_bar, SIGNAL(switchBuddies()), SLOT(onSwitchBuddies()));
}

void Designer::onSwitchWidgets()
{
    QDesignerFormWindowManagerInterface *formWindowManager = _iface->formWindowManager();
    for (int i=0; i<formWindowManager->formWindowCount(); ++i) {
        QDesignerFormWindowInterface *formWindow = formWindowManager->formWindow(i);
        if (formWindow == _form)
            formWindow->editWidgets();
    }
}

void Designer::onSwitchTabOrder()
{
    QDesignerFormWindowManagerInterface *formWindowManager = _designer->core()->formWindowManager();
    for (int i=0; i<formWindowManager->formWindowCount(); ++i) {
        QDesignerFormWindowInterface *formWindow = formWindowManager->formWindow(i);
        if (formWindow == _form)
            formWindow->setCurrentTool(3);
    }
}

void Designer::onSwitchBuddies()
{
    QDesignerFormWindowManagerInterface *formWindowManager = _designer->core()->formWindowManager();
    for (int i=0; i<formWindowManager->formWindowCount(); ++i) {
        QDesignerFormWindowInterface *formWindow = formWindowManager->formWindow(i);
        if (formWindow == _form)
            formWindow->setCurrentTool(2);
    }
}

void Designer::renderPyFile()
{
    QFileInfo info = QFileInfo(_fileName);
    QString pyFile = info.absoluteDir().path() % QDir::separator() % "Ui_" % info.baseName() % ".py";
    //qDebug() << pyFile;
    QStringList args;
    if (_project->pythonVersion() > 2)
        args << "--from-imports";
    args << "-o";
    args << pyFile;
    args << _fileName;
    QProcess proc;
    proc.start(Settings::instance()->pyuic4(), args);
    proc.waitForFinished();
}

void Designer::onNavigateToSlot(const QString& objectName, const QString& signalSignature, const QStringList& parameterNames)
{
    qDebug() << "navigate" << objectName << signalSignature << parameterNames;
}

}
